#include "TCPServer.h"
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>

namespace
{
	void *recv_socket_msg(void *ptr)
	{
		tcp_server *_tcp_server = (tcp_server *)ptr;
		_tcp_server->recv_msg();
	}

	void *send_socket_msg(void *ptr)
	{
		tcp_server *_tcp_server = (tcp_server *)ptr;
		_tcp_server->send_msg();	
	}

	unsigned long long get_current_millisecond()
	{
		struct timeval tv;
        gettimeofday(&tv, NULL);
        return ((unsigned long long)tv.tv_sec * 1000 + (unsigned long long)tv.tv_usec / 1000);
	}
}

void tcp_server::recv_buffer(int socket_fd)
{
	int ret = recv(socket_fd, buf, sizeof(buf), 0);
	if(ret <= 0)
	{
		close(socket_fd);

		std::cout << "close socket " << socket_fd << std::endl;

		for (int i = 0; i < MAXSIZE; ++i)
		{
			if(socket_array[i] == socket_fd)
				socket_array[i] = 0;
		}
	}
	else
	{
		if (ret < BUF_SIZE)
			memset(&buf[ret], '\0', 1);

		std::cout << buf << std::endl;

		std::string body = buf;
		int index = body.find(" ");
		if(index >= 0)
		{
			std::string com_port_str = body.substr(0, index);
			std::string com_cmd_str = body.substr(index + 1, body.length() - index - 1);	

			std::cout << "Port ^" << com_port_str << "$" << std::endl;
			std::cout << "CMD ^" << com_cmd_str << "$" << std::endl;

			Message message;
			message.com_port = atoi(com_port_str.c_str());
			const char * message_body = com_cmd_str.c_str();
			memcpy(message.message, message_body, strlen(message_body));
			message.message[strlen(message_body)] = '\0';

			_recv_message_queue->push_message(message);
		}
		else
		{
			std::cout << "未知的消息" << std::endl;
		}

		// Message message;
		// _recv_message_queue.pusb_back();
	}
}

void tcp_server::accept_socket(int socket_fd)
{
	socklen_t sin_size = sizeof(struct sockaddr_in);
	int accept_fd;
	if((accept_fd = accept(socket_fd,(struct sockaddr*) &remote_addr,&sin_size)) == -1)
	{
		throw "accept error";
		return;
	}

	std::cout << "Received a connection from " << (char*) inet_ntoa(remote_addr.sin_addr) << std::endl;

	bool is_find = false;
	for (int i = 0; i < MAXSIZE; ++i)
	{
		if(socket_array[i] == 0)
		{
			socket_array[i] = accept_fd;
			is_find = true;

			if(accept_fd > max_socket_fd)
				max_socket_fd = accept_fd;

			std::cout << "save socket_fd " << accept_fd << "\t" << i << std::endl;

			break;
		}
	}

	if(!is_find)
	{
		throw "No vacant position";
		close(accept_fd);
	}
}

// void *tcp_server::accept_msg(void *ptr)
// {
// 	tcp_server *server = (tcp_server *)ptr;
// 	while(1)
// 	{
// 		socklen_t sin_size = sizeof(struct sockaddr_in);
// 		int accept_fd;
// 		if((accept_fd = accept(socket_fd,(struct sockaddr*) &remote_addr,&sin_size)) == -1)
// 		{
// 			throw "accept error";
// 			continue;
// 		}

// 		printf("Received a connection from %s\n",(char*) inet_ntoa(remote_addr.sin_addr));
// 	}
// }

void tcp_server::recv_msg()
{
	fd_set recv_set;
	int recVal;
	int ret;
	while(1)
	{
		FD_ZERO(&recv_set);

		FD_SET(socket_fd, &recv_set);

		for (int i = 0; i < MAXSIZE; ++i)
		{
			if(socket_array[i] != 0)
			{
				FD_SET(socket_array[i], &recv_set);
			}
		}

		// std::cout << max_socket_fd + 1 << std::endl;


		struct timeval tv;
		tv.tv_sec = 1;
		tv.tv_usec = 0.0;
		recVal = select(max_socket_fd + 1, &recv_set, NULL, NULL, &tv);
	    switch(recVal)
	    {
	        case(0):
	        {
	        	// std::cout << "tcp recv time out" << std::endl;
	            break;
	        }
	        case(-1):
	        {
	        	perror("recv error");
	            break;
	        }
	        default:
	        {
	        	if (FD_ISSET(socket_fd, &recv_set))
    			{
    				std::cout << "new accept" << std::endl;
    				accept_socket(socket_fd);
    			}
	            
	        	for (int i = 0; i < MAXSIZE; ++i)
	        	{
	        		if(socket_array[i] != 0 && FD_ISSET(socket_array[i], &recv_set))
	        		{
	        			std::cout << "new recv data " << socket_array[i] << std::endl;
	        			recv_buffer(socket_array[i]);
	        		}	
	        	}

	            break;
	        }
	    }
	}
}

void tcp_server::send_msg()
{
	while(1)
	{
		struct Message message = _message_queue->pop_message();
		char c_body[1024];

		sprintf(c_body, "%d %s", message.com_port, message.message);

		std::cout << "Read Message " << c_body << std::endl;

		int send_count = 0;
		fd_set set;
		for (int i = 0; i < MAXSIZE; ++i)
		{
			if(socket_array[i] == 0)
				continue;

			std::cout << "Test fd " << socket_array[i] << std::endl;

			FD_ZERO(&set);
			FD_SET(socket_array[i], &set);

			struct timeval tv;
			tv.tv_sec = 0;
			tv.tv_usec = 0.0;
			if(select(socket_array[i] + 1, NULL, &set, NULL, &tv) > 0)
			{
				std::cout << socket_array[i] << " << " << c_body << std::endl;
				send(socket_array[i], c_body, strlen(c_body) , 0);

				++send_count;
			}
			else
			{
				std::cout << socket_array[i] << " 不可写入" << std::endl;
			}

			std::cout << "Send Finsh " << socket_array[i] << std::endl;
		}

		if(send_count == 0)
		{
			std::cout << "没有发现写入数据" << std::endl;

			for (int i = 0; i < MAXSIZE; ++i)
			{
				std::cout << " " << socket_array[i];
			}
			std::cout << std::endl;
		}
	}
}

tcp_server::tcp_server(int listen_port)
{
	if((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
	{
    	throw "socket() failed";
    }

    int on = 1;
    setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

	max_socket_fd = socket_fd;

    memset(&myserver,0,sizeof(myserver));
    myserver.sin_family = AF_INET;
    myserver.sin_addr.s_addr = htonl(INADDR_ANY);
    myserver.sin_port = htons(listen_port);

    std::cout << "开始尝试绑定" << std::endl;
	int socket_status = -1;
    unsigned long long start_time = get_current_millisecond();
    while(get_current_millisecond() - start_time < 10000)
    {
    	if ((socket_status = bind(socket_fd, (sockaddr*)&myserver, sizeof(myserver))) >= 0)
    		break;

    	std::cout << "尝试绑定失败 " << socket_status << std::endl;
    	sleep(1);
    }

	if(socket_status < 0) 
    {
    	throw "bind() failed";
    }

    std::cout << "成功绑定端口 " << listen_port << std::endl;

    if (listen(socket_fd, 10) < 0)
    {
    	throw "listen() failed";
    }
}

bool tcp_server::start_recv_msg(MessageQueue * mq)
{
	_recv_message_queue = mq;

	int ret;
	// ret = thread_create(&accept_thread_id, NULL, tcp_server::accept_msg, NULL);
	// if(ret)
	// {
	// 	count << "create pthread error" << endl;
	// 	return false;
	// }

	ret = pthread_create(&recv_thread_id, NULL, recv_socket_msg, this);
	if(ret)
	{
		std::cout << "create pthread error" << std::endl;
		return false;
	}

	return true;
}

bool tcp_server::stop_recv_msg()
{
	// pthread_exit(accept_thread_id);
	pthread_exit(&recv_thread_id);
	return true;
}

bool tcp_server::start_send_msg(MessageQueue * mq)
{
	_message_queue = mq;

	int ret = pthread_create(&send_thread_id, NULL, send_socket_msg, this);
	if(ret)
	{
		std::cout << "create pthread error" << std::endl;
		return false;
	}

	return true;
}

bool tcp_server::stop_send_msg()
{
	pthread_exit(&send_thread_id);
	return true;
}